#!/usr/bin/env lua
-- mpsd lua kodlaması
-- build system logic
--kütüphane eklemeleri
local mps_path=os.getenv("MPS_PATH")
if not mps_path then mps_path="/usr/milis/mps" end
package.cpath = package.cpath .. ";"..mps_path.."/lua/?.so"
package.path = package.path .. ";"..mps_path.."/lua/?.lua"
package.cpath = package.cpath .. ";"..mps_path.."/lua/ext/?.so"
package.path = package.path .. ";"..mps_path.."/lua/ext/?.lua"
local lip= require("LIP")
local lfs = require("lfs")
local util=require ("mps_helper")
local yaz=util.yaz
local _assert=util._assert
local has_value=util.has_value
local path_exists=util.path_exists
local shell=util.shell
local get_abspath=util.get_abspath
local get_basename=util.get_basename
local get_content=util.get_content

-- Paketleme dizini, yürürlük dosyasının oluşturulduğu konum
local paketleme_dizin=os.getenv("PAKETLEME_DIZIN")
if not paketleme_dizin then paketleme_dizin=lfs.currentdir() end

-- local mesajlar sonra import edilip, dil entegre sağlanacak
local messages={}
messages.operation_file_is_created=" yürürlük dosyası oluşturuldu."
messages.talimatdir_param_need=" talimat dizin parametresi yok"
messages.talimatdir_is_not_exist=" talimat dizini yok"
messages.talimat_is_not_exist=" talimat dosyası yok"
messages.talimatdir_format_error="talimat dizin formatı isim-surum-devir şeklinde olmalı!"
messages.hash_not_match="shasum uyumsuz kaynak arşiv dosyası!!!"

-- local değişkenler
local talimatdizin = ""
local talimatyol   = ""
local isim   = ""
local surum   = ""
local devir   = 0
local isd   = ""
local isd_ayrac   = "-"
local yururluk_dir = '/tmp'
local install_command = 'mps kur'
local config_dir = mps_path.."/conf/"
local global_variables = config_dir..'mpsd.conf'
local helper_functions = config_dir..'mpsd-helper.sh'

local renkyaz = true -- öntanımlı olarak renkli çıktı yazılır.
local talimatd_format_pattern="([%a%d-+]+)#([%d%a.]+)-([%d]+)"

-- talimat processing
local tproc={}

-- talimat kaynakların analizi
tproc.kaynak={}
function tproc.kaynak.github(value) 
	return "https://github.com/"..value.."/archive/v${surum}.tar.gz::$isim-$surum.tar.gz"  
end
function tproc.kaynak.bz2(value)   return value .. "/$isim-$surum.tar.bz2" end
function tproc.kaynak.gz(value)    return value .. "/$isim-$surum.tar.gz" end
function tproc.kaynak.xz(value)    return value .. "/$isim-$surum.tar.xz" end
function tproc.kaynak.tgz(value)   return value .. "/$isim-$surum.tgz" end

-- talimat gereklerin analizi
tproc.gerek={}
function tproc.gerek.derleme(value) 
	local betik=""
	for dep in value:gmatch('([^%s]+)') do
	--for _,dep in ipairs(value:split(" ")) do
		betik=betik..install_command.." "..dep.."\n"
	end
	return betik
end

-- talimat derle kısmının analizi
tproc.derle={}

tproc.derle.tipler={
gnu   = "./configure $confopt $extopt && make",
cmake = "cmake ./ && make",
py3   = "python3 setup.py build",
py2   = "python2 setup.py build",
meson = "cd $SRC && milis-meson $isim-$surum build $extopt",
ninja = "mkdir -p build && ninja -C build",
}

function tproc.derle.ekconf(value)    
	return 'export extopt="'..value..'"' 
end

function tproc.derle.yama(value)    
	if tproc.kaynaklar[tonumber(value)] then
		return "patch -Np1 -i $SRC/" .. tproc.kaynaklar[tonumber(value)]
	else
		return "patch -Np1 -i $SRC/" .. value 
	end
end
function tproc.derle.betik(value)   return value .. "\n" end
function tproc.derle.tip(value)     return tproc.derle.tipler[value]end
function tproc.derle.dosya(value)   return get_content(talimatdizin .."/"..value) end

-- talimat pakur kısmının analizi
tproc.pakur={}

tproc.pakur.tipler={
	gnu   = "make DESTDIR=$PKG install",
	py3   = "python3 setup.py install --root=${PKG} --optimize=1 --skip-build",
	py2   = "python2 setup.py install --root=${PKG} --optimize=1 --skip-build",
	ninja = "DESTDIR=$PKG ninja -C build install",
	meson = "cd $SRC && DESTDIR=$PKG ninja -C build install",
}

function tproc.pakur.betik(value)   return value end
function tproc.pakur.tip(value)     return tproc.pakur.tipler[value] end
function tproc.pakur.dosya(value)   return get_content(talimatdizin .."/"..value) end

-- elf dosyaların strip iptali için 
-- (mpsd.conf a müdahale için export ile kullanılacak)
function tproc.pakur.strip(value)   
	if has_value({"no","yok","0"},value) then
		--return "set_var \"STRIP\" \"-\""
		return "touch $PKG/.nostrip"
	else
		return "touch $PKG/.nostrip"
	end
end

-- strip karaliste belirtilmiş ise
function tproc.pakur.skliste(value)   
	return "set_var STRIP_KARALISTE=\""..value.."\""
end

-- 
function tproc.pakur.servis(value)   
	return ("cd /usr/milis/ayarlar/servisler\nmake DESTDIR=$PKG kur-%s\ncd -"):format(value)
end

-- isim, devir, sürüm değişken analiz işlevi
function get_isd(talimatdizin)
	isd = get_basename(talimatdizin)
	isim,surum,devir=isd:match(talimatd_format_pattern)
	if not (isim and surum and devir) then
		messages.talimatdir_format_error:yaz(0)
	end
	talimatdizin=get_abspath(talimatdizin)
	talimatyol=get_abspath(talimatdizin .. '/talimat')
end

-- split a string
function string:split(delimiter)
  local result = { }
  local from  = 1
  local delim_from, delim_to = string.find( self, delimiter, from  )
  while delim_from do
    table.insert( result, string.sub( self, from , delim_from-1 ) )
    from  = delim_to + 1
    delim_from, delim_to = string.find( self, delimiter, from  )
  end
  table.insert( result, string.sub( self, from  ) )
  return result
end



-- bir dosya urlsinin inen isminin alınması
function get_urlfsn(url)
	 local purl,dname=table.unpack(url:split("::"))
	 if dname == nil then
		local list=url:split("/")
		dname=list[#list]
	 end
	 return purl,dname
end

-- kaynakların analizi
tproc.kaynaklar={}
tproc.adkaynaklar={}
tproc.inkomutlar={}

function get_kaynaklar(talimat)
	local kaynaklar=""
	for key,c_value in ipairs(talimat.kaynak) do
		local key,value=c_value:match("(.*)@@(.*)")
		-- kaynak değerinin düzenlemesi
		if tproc.kaynak[key] then
			value=tproc.kaynak[key](value)
		end
		table.insert(tproc.kaynaklar,value)
		kaynaklar=kaynaklar .. value .. "\n"
		-- kaynakların kayıt adlarının alınması
		local url,dname=get_urlfsn(value)
		table.insert(tproc.adkaynaklar,dname)
		-- kaynakların indirme veya kopyalama surumlarının belirlenmesi 
		if key == "git" then
			table.insert(tproc.inkomutlar,"indir_git "..url.." "..dname)
		elseif key == "dosya" then
			table.insert(tproc.inkomutlar,("cp -f ${TALIMAT_DIZIN}/%s ${KAYNAKLAR_DEPO}/"):format(dname))
		else
			table.insert(tproc.inkomutlar,"indir_wget "..url.." "..dname)
		end
	end
	return kaynaklar
end

-- derle işlevi hazırlanması
function get_derle(talimat)
	local betik=""
	for key,c_value in ipairs(talimat.derle) do
		-- key e göre derle analiz
		local key,value=c_value:match("(.*)@@(.*)")
		-- ilgili anahtar işleve göre betik düzenlenecek.
		if tproc.derle[key] == nil then
			("derle kısmında tanımsız anahtar:" .. key):yaz(0)
		else
			betik=betik .. tproc.derle[key](value) .."\n"
		end
	end
	return betik
end

-- pakur işlev hazırlanması
function get_pakur(talimat)
	local betik=""
	for key,c_value in ipairs(talimat.pakur) do
		-- key e göre derle analiz
		local key,value=c_value:match("(.*)@@(.*)")
		-- ilgili anahtar işleve göre betik düzenlenecek.
		if tproc.pakur[key] == nil then
			("pakur kısmında tanımsız anahtar:" .. key):yaz(0)
		else
			local _val=tproc.pakur[key](value)
			if _val ~= nil  then
				betik=betik .. _val .. "\n"
			else
				("pakur kısmında uyumsuz deger:" .. value):yaz(0)
			end
		end
	end
	return betik
end

-- derleme gerek işlev hazırlanması
function get_bdeps(talimat)
	local betik=""
	if talimat.gerek then
		for key,value in pairs(talimat.gerek) do
			if tproc.gerek[key] ~= nil then
				betik=tproc.gerek[key](value)
			end
		end
	end
	if betik == "" then betik="echo \"derleme gerekleri yok\"\n" end
	return betik
end

-- kaynakların indirme veya kopyalanma işlevinin hazırlanması
function get_download()
	local betik=""
	for _,inkomut in ipairs(tproc.inkomutlar) do
		betik=betik..inkomut.."\n"
	end
	return betik
end

-- talimat dosyasının sha256sum değerinin alınması
function get_talimathash()
	return shell("sha256sum "..talimatyol.." | awk '{print $1}'")
end

-- indirilen kaynakların hash kontrolünün yapılması
function get_hashcheck(talimat)
	local betik,hashline,iline,hvalue,file=""
	-- mpsd-helper.sh  
	local hash_kontrol_komut="[ $? -eq 1 ] && hata_olustu \""..messages.hash_not_match.."\""
	function hash_betik_al(hashler,komut)
		for key,hvalue in pairs(hashler) do
			local kaynak=tproc.kaynaklar[key]
			if kaynak ~= nil then 
				_,dname=get_urlfsn(kaynak)
				--hashline="hash değeri alınsa doğru da olsa alınacak?"
				iline="echo \""..hvalue.."  ${KAYNAKLAR_DEPO}/"..dname.."\" | "..komut.." --check\n"
				iline=iline..hash_kontrol_komut.."\n"
			else
				(key.." sıralı linke ait hash değeri bulunamadı!"):yaz(0)
			end
			betik=betik..iline.."\n"
		end
	end
	
	if talimat.sha256 then 
		hash_betik_al(talimat.sha256,"sha256sum")
	end
	if talimat.sha512 then 
		hash_betik_al(talimat.sha512,"sha512sum")
	end
	if betik == "" then betik="echo \"hash kontrol pas geçildi\"\n" end
	return betik
end

-- indirilen kaynakların dışarı çıkarılması
function get_extract()
	local betik=""
	for _,kaynak in ipairs(tproc.adkaynaklar) do
		betik=betik.."echo \""..kaynak.."\" >> $SRC/arsiv.list\n"	
	end
	if betik ~= "" then
		betik=betik.."kaynak_cikar\n"
	end
	return betik
end

-- girdilerin kontrolü 
local param=arg[1]

_assert(param,messages.talimatdir_param_need)
_assert(path_exists(param),messages.talimatdir_is_not_exist)
_assert(path_exists(param.."/talimat"),messages.talimat_is_not_exist)

talimatdizin=arg[1]

-- isim, sürüm, devir değişkenlerinin ayrıştırılması ve talimatyol atanması
get_isd(talimatdizin)

--local talimat = ini.parse_file(talimatyol)
local talimat = lip.load(talimatyol,{"derle","pakur","kaynak"})

-- talimat üstbilgi değişkenlerin atanması
-- altta atandı
-- talimat kaynakların analizi

-- yürürlük dosyasının ilklenmesi
-- local yururluk_file=yururluk_dir .. "/"..isd..".yur"
-- local yururluk_file=talimatdizin .. "/"..isd..".yur"
local yururluk_file=paketleme_dizin .. "/"..isim..".yur"
local yururluk = io.open(yururluk_file ,"w")

-- yürürlük şablonun atanması
local yur_content = require("yursablon")

yur_content=yur_content:gsub("@([%w_]+)@",{
		THASH=get_talimathash(),
		TALIMAT_DIZIN=talimatdizin,
		GLOBALS=get_content(global_variables),--"source ./"..global_variables,
		FUNCTIONS=get_content(helper_functions),--"source ./"..global_variables,
		GENTIME="# "..os.date("%x %H:%M:%S") .."\n",
		TANIM=talimat.paket.tanim,
		URL=talimat.paket.url,
		PAKETCI=talimat.paket.paketci,
		GRUP=talimat.paket.grup,
		ISIM=isim,
		SURUM=surum,
		DEVIR=devir,
		KAYNAK=get_kaynaklar(talimat),
		DERLE=get_derle(talimat),
		PAKUR=get_pakur(talimat),
		--GEREK_KUR=get_bdeps(talimat),
		DOWNLOAD=get_download(),
		HASH_CHECK=get_hashcheck(talimat),
		EXTRACT=get_extract(),
})

yururluk:write(yur_content)

yururluk:close();
shell("chmod +x "..yururluk_file);
(yururluk_file..messages.operation_file_is_created):yaz(1);
-- ("farklı tipte derlemeler yapılacak,"):yaz(2);
-- ("arsiv.bilgi!,"):yaz(2)

